#pragma once
#include<string>
#include<fstream>
#include<vector>
#include<boost/algorithm/string.hpp>
#include"cppjieba/Jieba.hpp"
#include<vector>
#include<mutex>
#include<unordered_map>
#include"log.hpp"

namespace Util_ns
{
    class File_Util
    {
        public:
            static bool ReadFile(const std::string& path,std::string* out)
            {
                std::ifstream ifs(path);
                if(!ifs.is_open())
                    return false;
                
                std::string line;
                while(std::getline(ifs,line))
                {
                    (*out) += line;
		            (*out) += "\n";
                }
                
                ifs.close();
                return true;
            }
    };

    class String_Util
    {
        public:
            static void Spilt(const std::string& s,std::vector<std::string>* res,const std::string seq)
            {
                boost::split(*res,s,boost::is_any_of(seq),boost::token_compress_on);
            }
    };

    const char* const DICT_PATH = "./dict/jieba.dict.utf8";
    const char* const HMM_PATH = "./dict/hmm_model.utf8";
    const char* const USER_DICT_PATH = "./dict/user.dict.utf8";
    const char* const IDF_PATH = "./dict/idf.utf8";
    const char* const STOP_WORD_PATH = "./dict/stop_words.utf8";

    class Jieba_Util
    {
        private: 
            cppjieba::Jieba _jieba;
            std::unordered_set<std::string> _stopmp;
            Jieba_Util():_jieba(DICT_PATH,
                HMM_PATH,
                USER_DICT_PATH,
                IDF_PATH,
                STOP_WORD_PATH)
            {

            }

            Jieba_Util(const Jieba_Util&)=delete;
            Jieba_Util& operator=(const Jieba_Util&)=delete;

            static Jieba_Util* _instance;
        public:
            static Jieba_Util* GetInstance()
            {
                std::mutex _mutex;
                if(_instance == nullptr)
                {
                    _mutex.lock();
                    if(_instance == nullptr)
                    {
                        _instance = new Jieba_Util;
                        _instance->LoadStopWord();
                    }
                    _mutex.unlock();
                }

                return _instance;
            }

            void LoadStopWord()
            {
                std::ifstream ifs(STOP_WORD_PATH,std::ios::in);

                if(!ifs.is_open())
                {
                    LOG(ERROR,"Stop word Load err");
                    return;
;                }

                std::string line;
                while(std::getline(ifs,line))
                {
                    if(!line.empty())
                    {
                        _stopmp.insert(line);
                    }
                }
            }

            void CutStringHelper(const std::string& str,std::vector<std::string>* res)
            {
                _jieba.CutForSearch(str,*res);

                for(auto iter = res->begin();iter != res->end();)
                {
                    if(_stopmp.find(*iter) != _stopmp.end())
                    {
                        res->erase(iter);
                    }
                    else
                    {
                        iter++;
                    }
                }
            }
        public:
            static void CutString(const std::string& str,std::vector<std::string>* res)
            {
                GetInstance()->CutStringHelper(str,res);
            }
    };

    Jieba_Util* Jieba_Util::_instance = nullptr;

}
